/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

package xowl.generator.proxy;

/**
 *
 * @author Laurent WOUTERS
 */
public class PropImplWriter {
    public static void write(java.io.Writer writer, xowl.generator.PropertyImplementation impl) throws java.io.IOException {
        boolean isInTypeRestrictionChain = false;
        for (xowl.generator.PropertyInterface inter : impl.getInterfaces()) {
            if (inter.isInTypeRestrictionChain()) {
                isInTypeRestrictionChain = true;
                break;
            }
        }
        
        String property = impl.getProperty().getName();
        
        writer.append("    // <editor-fold defaultstate=\"collapsed\" desc=\"Property " + property + "\">\n");
        writer.append("    private static String propertyIRI_" + property + " = \"" + impl.getProperty().getOWLProperty().getInterpretationOf().getHasIRI().getHasValue() + "\";\n");
        writer.append("    private xowl.lang.owl2.IRI property_" + property + ";\n");
        writer.append("    private xowl.lang.owl2.IRI getProperty_" + property + "() {\n");
        writer.append("        if (property_" + property + " != null) return property_" + property + ";\n");
        writer.append("        property_" + property + " = repository.getIRI(propertyIRI_" + property + ");\n");
        writer.append("        return property_" + property + ";\n");
        writer.append("    }\n");

        if (!impl.getProperty().isObjectProperty())
            write_Datatype(writer, impl);
        else {
            for (xowl.generator.PropertyInterface inter : impl.getInterfaces())
                write_ObjectInterface(writer, inter, impl, isInTypeRestrictionChain);
        }
        writer.append("    // </editor-fold>\n");
    }

    private static void write_Datatype(java.io.Writer writer, xowl.generator.PropertyImplementation impl) throws java.io.IOException {
        for (xowl.generator.PropertyInterface inter : impl.getInterfaces()) {
            if (inter.isVector())
                write_DatatypeInterfaceVector(writer, inter, impl);
            else
                write_DatatypeInterfaceScalar(writer, inter, impl);
        }
    }
    private static void write_DatatypeInterfaceScalar(java.io.Writer writer, xowl.generator.PropertyInterface inter, xowl.generator.PropertyImplementation impl) throws java.io.IOException {
        String property = inter.getProperty().getName();
        String type = impl.getRepresentationRange();
        writer.append("    public boolean set" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "(" + type + " elem) {\n");
        writer.append("        removeAllData(getProperty_" + property + "());\n");
        writer.append("        return addAxiom(createDataAxiom(getProperty_" + property + "(), elem));\n");
        writer.append("    }\n");
        writer.append("    public " + type + " get" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "() {\n");
        writer.append("        java.util.List<Object> previous = getAllData(getProperty_" + property + "());\n");
        writer.append("        if (previous.isEmpty()) return null;\n");
        writer.append("        return (" + type + ")previous.get(0);\n");
        writer.append("    }\n");
    }
    private static void write_DatatypeInterfaceVector(java.io.Writer writer, xowl.generator.PropertyInterface inter, xowl.generator.PropertyImplementation impl) throws java.io.IOException {
        String property = inter.getProperty().getName();
        String type = impl.getRepresentationRange();
        writer.append("    public boolean add" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "(" + type + " elem) {\n");
        writer.append("        return addAxiom(createDataAxiom(getProperty_" + property + "(), elem));\n");
        writer.append("    }\n");
        writer.append("    public boolean remove" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "_remve(" + type + " elem) {\n");
        writer.append("        return removeAxiom(ontology, createDataAxiom(getProperty_" + property + "(), elem));\n");
        writer.append("    }\n");
        writer.append("    public java.util.Collection<" + type + "> getAll" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "() {\n");
        writer.append("        java.util.List<Object> previous = getAllData(getProperty_" + property + "());\n");
        writer.append("        java.util.List<" + type + "> results = new java.util.ArrayList<" + type + ">();\n");
        writer.append("        for (Object o : previous) results.add((" + type + ")o);\n");
        writer.append("        return results;\n");
        writer.append("    }\n");
    }

    private static void write_ObjectInterface(java.io.Writer writer, xowl.generator.PropertyInterface inter, xowl.generator.PropertyImplementation impl, boolean isInTypeRestrictChain) throws java.io.IOException {
        xowl.generator.ClassGenerator interfaceRange = inter.getRangeClass();
        if (inter.isVector()) {
            if (!interfaceRange.isAbstract())
                write_ObjectInterfaceVector_Concrete(writer, inter, impl, isInTypeRestrictChain);
            else
                write_ObjectInterfaceVector_Abstract(writer, inter, impl, isInTypeRestrictChain);
        } else {
            if (!interfaceRange.isAbstract())
                write_ObjectInterfaceScalar_Concrete(writer, inter, impl, isInTypeRestrictChain);
            else
                write_ObjectInterfaceScalar_Abstract(writer, inter, impl, isInTypeRestrictChain);
        }
    }
    private static void write_ObjectInterfaceScalar_Concrete(java.io.Writer writer, xowl.generator.PropertyInterface inter, xowl.generator.PropertyImplementation impl, boolean isInTypeRestrictChain) throws java.io.IOException {
        String property = inter.getProperty().getName();
        String interType = inter.getRangeClass().getJavaName();
        String value = "elem.getEntity()";
        if (interType.equals("java.lang.Class"))
            value = "elem";
        else if (interType.equals("java.lang.Object"))
            value = "getEntityFor(elem)";
        writer.append("    public boolean set" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "(" + interType + " elem) {\n");
        writer.append("        removeAllObjects(getProperty_" + property + "());\n");
        writer.append("        return addAxiom(createObjectAxiom(getProperty_" + property + "(), " + value + "));\n");
        writer.append("    }\n");
        if (!isInTypeRestrictChain)
            writer.append("    public " + interType + " get" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "() {\n");
        else
            writer.append("    public " + interType + " get" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "As(" + interType + " type) {\n");
        writer.append("        java.util.List<xowl.lang.runtime.Entity> previous = getAllEntities(getProperty_" + property + "());\n");
        writer.append("        if (previous.isEmpty()) return null;\n");
        if (interType.equals("java.lang.Class"))
            writer.append("        return getClassFor(previous.get(0));\n");
        else if (interType.equals("java.lang.Object"))
            writer.append("        return getObjectFor(previous.get(0));\n");
        else
            writer.append("        return " + inter.getRangeClass().getJavaName() + ".get(repository, previous.get(0));\n");
        writer.append("    }\n");
    }
    private static void write_ObjectInterfaceScalar_Abstract(java.io.Writer writer, xowl.generator.PropertyInterface inter, xowl.generator.PropertyImplementation impl, boolean isInTypeRestrictChain) throws java.io.IOException {
        String property = inter.getProperty().getName();
        String interType = inter.getRangeClass().getJavaName();
        writer.append("    public boolean set" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "(" + interType + " elem) {\n");
        writer.append("        removeAllObjects(getProperty_" + property + "());\n");
        writer.append("        return addAxiom(createObjectAxiom(getProperty_" + property + "(), elem.getEntity()));\n");
        writer.append("    }\n");
        if (!isInTypeRestrictChain)
            writer.append("    public " + interType + " get" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "() {\n");
        else
            writer.append("    public " + interType + " get" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "As(" + interType + " type) {\n");
        writer.append("        java.util.List<ProxyObject> previous = getAllObjects(getProperty_" + property + "());\n");
        writer.append("        if (previous.isEmpty()) return null;\n");
        writer.append("        return (" + interType + ")previous.get(0);\n");
        writer.append("    }\n");
    }
    private static void write_ObjectInterfaceVector_Concrete(java.io.Writer writer, xowl.generator.PropertyInterface inter, xowl.generator.PropertyImplementation impl, boolean isInTypeRestrictChain) throws java.io.IOException {
        String property = inter.getProperty().getName();
        String interType = inter.getRangeClass().getJavaName();
        String value = "elem.getEntity()";
        if (interType.equals("java.lang.Class"))
            value = "elem";
        else if (interType.equals("java.lang.Object"))
            value = "getEntityFor(elem)";
        writer.append("    public boolean add" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "(" + interType + " elem) {\n");
        writer.append("        return addAxiom(createObjectAxiom(getProperty_" + property + "(), " + value + "));\n");
        writer.append("    }\n");

        writer.append("    public boolean remove" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "(" + interType + " elem) {\n");
        writer.append("        return removeAxiom(createObjectAxiom(getProperty_" + property + "(), " + value + "));\n");
        writer.append("    }\n");
        if (!isInTypeRestrictChain)
            writer.append("    public java.util.Collection<" + interType + "> getAll" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "() {\n");
        else
            writer.append("    public java.util.Collection<" + interType + "> getAll" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "As(" + interType + " type) {\n");
        writer.append("        java.util.List<xowl.lang.runtime.Entity> previous = getAllEntities(getProperty_" + property + "());\n");
        writer.append("        java.util.List<" + interType + "> results = new java.util.ArrayList<" + interType + ">();\n");
        writer.append("        for (xowl.lang.runtime.Entity entity : previous)\n");
        if (interType.equals("java.lang.Class"))
            writer.append("            results.add(getClassFor(entity));\n");
        else if (interType.equals("java.lang.Object"))
            writer.append("            results.add(getObjectFor(entity));\n");
        else
            writer.append("            results.add(" + inter.getRangeClass().getJavaName() + ".get(repository, entity));\n");
        writer.append("        return results;\n");
        writer.append("    }\n");
    }
    private static void write_ObjectInterfaceVector_Abstract(java.io.Writer writer, xowl.generator.PropertyInterface inter, xowl.generator.PropertyImplementation impl, boolean isInTypeRestrictChain) throws java.io.IOException {
        String property = inter.getProperty().getName();
        String interType = inter.getRangeClass().getJavaName();
        writer.append("    public boolean add" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "(" + interType + " elem) {\n");
        writer.append("        return addAxiom(createObjectAxiom(getProperty_" + property + "(), elem.getEntity()));\n");
        writer.append("    }\n");

        writer.append("    public boolean remove" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "(" + interType + " elem) {\n");
        writer.append("        return removeAxiom(createObjectAxiom(getProperty_" + property + "(), elem.getEntity()));\n");
        writer.append("    }\n");
        if (!isInTypeRestrictChain)
            writer.append("    public java.util.Collection<" + interType + "> getAll" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "() {\n");
        else
            writer.append("    public java.util.Collection<" + interType + "> getAll" + String.valueOf(property.charAt(0)).toUpperCase() + property.substring(1) + "As(" + interType + " type) {\n");
        writer.append("        java.util.List<ProxyObject> previous = getAllObjects(getProperty_" + property + "());\n");
        writer.append("        java.util.List<" + interType + "> results = new java.util.ArrayList<" + interType + ">();\n");
        writer.append("        for (ProxyObject entity : previous)\n");
        writer.append("            results.add((" + interType + ")entity);\n");
        writer.append("        return results;\n");
        writer.append("    }\n");
    }
}
